home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 1 (Walnut Creek)
/
Aminet - June 1993 [Walnut Creek].iso
/
aminet
/
os20
/
cli
/
ls_4_7ljr.lha
/
ls-4.7ljr
/
ls.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-10-26
|
37KB
|
1,531 lines
/*
* LS 4.7ljr
*
* This software is Copyright © 1989, 1990, 1991, 1992 Loren J. Rittle.
* This software is Copyright for the sole purpose of protecting
* the fact that this is indeed free software.
*
* This software is wholly, but at this point loosely, based upon
* Justin V. McCormick's PD LS ``V3.1 July 29, 1989'' with
* enhancements and bug fixes by the copyright holder, Loren J. Rittle.
*/
/* This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
See COPYING and ls.doc for copyright and copying information. */
/* If you generate a new version for release to the public,
please replace my initials 'ljr' with your own (so the public
knows who to blame... :-). Your version should be marked
(at least in the source and documentation) as having been based
upon the 'ljr' strain version <current version number>.
On the other hand, you can send bug reports and patches to
rittle@comm.mot.com for me to incorporate into my next major
release.
Loren J. Rittle
rittle@comm.mot.com */
#include "ls.h"
#define MAXARG 100
#define PADTABSIZE 256
#define WORKSIZE 1024
#if !defined(VERSION_STRING) || !defined(SHORT_DATE_STRING) || !defined(DATE_STRING)
#error VERSION_STRING, SHORT_DATE_STRING and DATE_STRING must be defined.
#error Use smake to compile.
#endif
void _CXBRK (int sig);
void _CXBRK (int sig) {}
BYTE version[]=
"\0$VER: ls-(ljr_strain) " VERSION_STRING " (" SHORT_DATE_STRING ")";
BYTE shortusage[]= "LS Version " VERSION_STRING "ljr, " DATE_STRING "\n\
Usage: ls [-h?acdefklnrstw1ADFHIMNOPRTX <args>] [path] ...\n";
BYTE fullusage[]= "\
a List all entries A Display entries across line\n\
c Show filenotes D Show dirs last\n\
d About dirs F <format> Format output\n\
e Sort by extension H No headings and subtotals\n\
f Only show files I <pattern> Ignore pattern\n\
k Kill ANSI codes M Mixed output files and dirs\n\
l Long listing N <date> Show newer than date\n\
n No sort O <date> Show older than date\n\
r Reverse sort P Show full pathnames\n\
s Sort by size R Recursive listing\n\
t Sort by date T Total all subtotals\n\
w <string> Set %%w X <wide> Set output columns\n\
1 One entry per line\n";
BYTE deffmtstr[]= "%p %5b %8s %d %n%w%C\\n";
BYTE deffullstr[]= "%n\\n";
BYTE LongFmtStr[]= "%ld";
BYTE totalfmtstr[]= "Dirs:%-4ld Files:%-4ld Blocks:%-5ld Bytes:%-8ld\n";
BYTE TotHeaderMsg[]= "Totals:\n";
BYTE ErrFmtStr[]= "ls: %s\n";
BYTE BadOptFmtStr[]= "ls: Unknown option -%lc\n";
BYTE OptNeedsArgStr[]= "ls: Option -%lc needs argument\n";
BYTE NoExamFmtStr[]= "ls: Cannot examine file or directory, Error #%ld\n";
BYTE NoFindFmtStr[]= "ls: '%s' not found\n";
BYTE NotGoodDateStr[]= "ls: '%s' not a date\n";
BYTE NoWildPathMsg[]= "Unable to pattern match paths";
BYTE NoRAMMsg[]= "No RAM";
BYTE ParseErrorMsg[]= "ParsePattern Error";
BYTE NameFromLockMsg[]= "NameFromLock Error";
BYTE ExNextMsg[]= "ExNext Error";
BYTE NoCurrentDirMsg[]= "No Current Directory";
/* these are basically related to fib_DirEntryType after being
remaped by RemapDirEntryType (). */
struct highlight highlight_tabx[13] =
{
/* -7 FILE_DEFAULT */ {"", "", 0},
/* -6 LINKFILE_EXE */ {"\x9b" "1m", "\x9b" "22m", 0},
/* -5 FILE_EXE */ {"", "", 0},
/* -4 LINKFILE */ {"\x9b" "1m", "\x9b" "22m", 0},
/* -3 FILE */ {"", "", 0},
/* -2 SOFTLINK_EXE */ {"\x9b" "3m", "\x9b" "23m", 0},
/* -1 SOFTLINK */ {"\x9b" "3m", "\x9b" "23m", 0},
/* 0 COMMENT */ {"\x9b" "2m/* ", " */\x9b" "22m", 6},
/* 1 ROOT */ {"\x9b" "2m", "\x9b" "22m", 0},
/* 2 USERDIR */ {"\x9b" "2m", "\x9b" "22m", 0},
/* 3 LABEL */ {"\x9b" "2m", "\x9b" "22m", 0},
/* 4 LINKDIR */ {"\x9b" "2;1m", "\x9b" "22m", 0},
/* 5 DIR_DEFAULT */ {"", "", 0},
}, *highlight_tab = &highlight_tabx[7];
#define HIGHLIGHT_MAX 5
#define HIGHLIGHT_MIN -7
#define HI_FILE_DEFAULT -7
#define HI_LINKFILE_EXE -6
#define HI_FILE_EXE -5
#define HI_LINKFILE -4
#define HI_FILE -3
#define HI_SOFTLINK_EXE -2
#define HI_SOFTLINK -1
#define HI_COMMENT 0
#define HI_ROOT 1
#define HI_USERDIR 2
#define HI_LABEL 3
#define HI_LINKDIR 4
#define HI_DIR_DEFAULT 5
struct highlight highlight_null = {"", "", 0};
struct highlight highlight_cursor = {"\x9b" " p", "\x9b" "0 p", 0};
struct DateStamp theolddate;
struct DateStamp thenewdate;
struct FileLock *CurFLock;
/* Don't change order of next four entries. Order needs to be preserved
for VPrintf calls. */
LONG gdircount;
LONG gfilecount;
LONG gtotblocks;
LONG gtotbytes;
/* end of important order */
/* Don't change order of next four entries. Order needs to be preserved
for VPrintf calls. */
LONG dircount;
LONG filecount;
LONG totblocks;
LONG totbytes;
/* end of important order */
LONG maxnamlen;
enum sortkey
{
sort_alpha, sort_size, sort_date, sort_extension, sort_none
} sortkey;
char *wflag = "\n";
BYTE padtab[PADTABSIZE];
BYTE thePath[WORKSIZE * 2 + 4];
BYTE theDirPat[WORKSIZE];
BYTE theFilePat[WORKSIZE];
BYTE theDirPatParsed[WORKSIZE * 2 + 2];
BYTE theFilePatParsed[WORKSIZE * 2 + 2];
BYTE workstr[WORKSIZE + 64];
BYTE theblksstr[64];
BYTE thedatestr[64];
BYTE theprotstr[64];
BYTE thesizestr[64];
BYTE thehexsizestr[64];
BYTE thetimesizestr[64];
LONG CurWinCols;
BYTE *curpath;
BYTE *thefmtstr = deffmtstr;
struct AnAntiPattern *TheAntiPatterns;
int BREAKFLAG;
int CONSOLE;
int HIDEDIRS;
int LISTALL;
int LONGLIST;
int NOTEFLAG;
int PATHNAMED;
int REVFLAG;
int ABOUTDIRS;
int FULLPATHNAMES;
int TOTALIZE;
int NOHEADERS;
int FILESFIRST;
int MIXFILESDIRS;
int SHOWOLDERTHAN;
int SHOWNEWERTHAN;
int SHOWHIDDEN;
int ACROSSLIST;
static int CompareExtensions (char *, char *);
static int CmpDateBounds (struct DateStamp *);
static int CompFibs (enum sortkey, struct FileInfoBlock *, struct FileInfoBlock *);
static void WriteErrorString (BYTE *,...);
static void TestBreak (void);
static void DateStr (BYTE *, struct DateStamp *);
static int StrDate (BYTE *, struct DateStamp *);
static void CleanUp (BYTE *, LONG, LONG);
static void AddAntiPattern (BYTE *);
static void Usage (int);
void kput1 (void);
static void GetWinBounds (LONG *, LONG *, LONG);
static int FillFibEntry (struct MinList *, struct FileInfoBlock *);
static struct FibEntry *ModNextFib (struct FibEntry *, LONG);
static void SListDir (struct MinList *);
static void LListEntry (struct FileInfoBlock *);
static void LListDir (struct MinList *);
static void FreeAllFibs (struct MinList *);
static struct MinList *GetDir (struct FileLock *, struct FileInfoBlock *);
static void DirIt (struct FileLock *, BYTE *);
static void GetCLIArgs (BYTE *, LONG *, BYTE **);
static LONG ParseCmdOptions (LONG, LONG, BYTE **);
static char *stpcpy (char *, char *);
int stricmp (char *, char *);
static void RemapDirEntryType (struct FileInfoBlock *a);
static void RemapDirEntryType (struct FileInfoBlock *a)
{
/* Remap fib_DirEntryType to allow for easier usage later. */
/* See order in highlight_tab for more details. */
switch (a->fib_DirEntryType)
{
case ST_LINKFILE:
case ST_FILE:
if ((a->fib_Protection & FIBF_SCRIPT) ||
(~a->fib_Protection & FIBF_EXECUTE))
a->fib_DirEntryType -= 2;
break;
case ST_ROOT:
case ST_USERDIR:
case ST_LINKDIR:
break;
case ST_SOFTLINK:
if ((a->fib_Protection & FIBF_SCRIPT) ||
(~a->fib_Protection & FIBF_EXECUTE))
a->fib_DirEntryType = HI_SOFTLINK_EXE;
else
a->fib_DirEntryType = HI_SOFTLINK;
break;
default:
if (a->fib_DirEntryType >= 0)
a->fib_DirEntryType = HI_DIR_DEFAULT;
else
a->fib_DirEntryType = HI_FILE_DEFAULT;
break;
}
}
static char *stpcpy (char *a, char *b)
{
while (*a++ = *b++)
;
return --a;
}
static int CompareExtensions (char *namea, char *nameb)
{
char *taila = strrchr (namea, '.');
char *tailb = strrchr (nameb, '.');
if (taila)
return tailb ? stricmp (taila, tailb) : 1;
else
return tailb ? -1 : 0;
}
static int CmpDateBounds (struct DateStamp *tdate)
{
if ((SHOWNEWERTHAN) && (CompareDates (&thenewdate, tdate) <= 0))
return 0;
if ((SHOWOLDERTHAN) && (CompareDates (tdate, &theolddate) <= 0))
return 0;
return 1;
}
static int CompFibs (enum sortkey keytype, struct FileInfoBlock *a, struct FileInfoBlock *b)
{
int rc;
if (((a->fib_DirEntryType < 0) && (b->fib_DirEntryType > 0)) ||
((a->fib_DirEntryType > 0) && (b->fib_DirEntryType < 0)))
if (!(MIXFILESDIRS))
return (FILESFIRST) ?
(a->fib_DirEntryType < 0) :
(a->fib_DirEntryType > 0);
switch (keytype)
{
case sort_size:
rc = b->fib_Size - a->fib_Size;
goto like;
case sort_date:
rc = CompareDates (&b->fib_Date, &a->fib_Date);
goto like;
case sort_extension:
rc = CompareExtensions (b->fib_FileName, a->fib_FileName);
like:
if (rc > 0)
return !REVFLAG;
if (rc < 0)
return REVFLAG;
case sort_alpha:
if (stricmp (b->fib_FileName, a->fib_FileName) > 0)
return !REVFLAG;
else
return REVFLAG;
case sort_none:
return REVFLAG;
default:
return REVFLAG;
}
}
static void WriteErrorString (BYTE *tstring, ...)
{
struct Process *procp = (struct Process *) FindTask (0L);
BPTR StdErr = procp->pr_CES;
VFPrintf (StdErr ? StdErr : Output (), tstring, (LONG *) & tstring + 1);
}
static void TestBreak (void)
{
if (CheckSignal (SIGBREAKF_CTRL_C))
{
PutStr ("*** Break: ls\n");
BREAKFLAG = 1;
}
}
static void DateStr (BYTE *s, struct DateStamp *ds)
{
char StrDate[LEN_DATSTRING], StrTime[LEN_DATSTRING];
struct DateTime dt;
struct DateStamp cds;
dt.dat_Stamp = *ds;
dt.dat_Format = FORMAT_DOS;
dt.dat_Flags = 0;
dt.dat_StrDay = NULL;
dt.dat_StrDate = StrDate;
dt.dat_StrTime = StrTime;
if (!DateToStr (&dt))
{
strcpy (s, "Bad 1 Date");
return;
}
s[0] = StrDate[3];
s[1] = StrDate[4];
s[2] = StrDate[5];
s[3] = ' ';
s[4] = (StrDate[0] == '0') ? ' ' : StrDate[0];
s[5] = StrDate[1];
s[6] = ' ';
DateStamp (&cds);
if (((cds.ds_Days - ds->ds_Days) > 180) || ((cds.ds_Days - ds->ds_Days) < 0))
{
s[7] = ' ';
if (ds->ds_Days < 8035)
{
s[8] = '1';
s[9] = '9';
}
else
{
s[8] = '2';
s[9] = '0';
}
s[10] = StrDate[7];
s[11] = StrDate[8];
}
else
{
s[7] = StrTime[0];
s[8] = StrTime[1];
s[9] = ':';
s[10] = StrTime[3];
s[11] = StrTime[4];
}
s[12] = '\0';
}
static int StrDate (BYTE *s, struct DateStamp *ds)
{
char StrDate[LEN_DATSTRING], StrTime[LEN_DATSTRING];
struct DateTime dt;
switch (strlen (s))
{
case 17:
/* Standard "MMM DD HH:MM YYYY" 'ls' format */
if ((StrDate[0] = s[4]) == ' ')
StrDate[0] = '0';
StrDate[1] = s[5];
StrDate[2] = '-';
StrDate[3] = s[0];
StrDate[4] = s[1];
StrDate[5] = s[2];
StrDate[6] = '-';
StrDate[7] = s[15];
StrDate[8] = s[16];
StrDate[9] = '\0';
StrTime[0] = s[7];
StrTime[1] = s[8];
StrTime[2] = s[9];
StrTime[3] = s[10];
StrTime[4] = s[11];
StrTime[5] = ':';
StrTime[6] = '0';
StrTime[7] = '0';
StrTime[8] = '\0';
break;
case 18:
/* Standard "DD-MMM-YY HH:MM:SS" AmigaDOS 'date' and internal format */
StrDate[0] = s[0];
StrDate[1] = s[1];
StrDate[2] = s[2];
StrDate[3] = s[3];
StrDate[4] = s[4];
StrDate[5] = s[5];
StrDate[6] = s[6];
StrDate[7] = s[7];
StrDate[8] = s[8];
StrDate[9] = '\0';
StrTime[0] = s[10];
StrTime[1] = s[11];
StrTime[2] = s[12];
StrTime[3] = s[13];
StrTime[4] = s[14];
StrTime[5] = s[15];
StrTime[6] = s[16];
StrTime[7] = s[17];
StrTime[8] = '\0';
break;
default:
return 1;
}
dt.dat_Format = FORMAT_DOS;
dt.dat_Flags = 0;
dt.dat_StrDay = NULL;
dt.dat_StrDate = StrDate;
dt.dat_StrTime = StrTime;
if (!StrToDate (&dt))
return 1;
*ds = dt.dat_Stamp;
return 0;
}
static void CleanUp (BYTE *exit_msg, LONG exit_status, LONG result2)
{
if (CurFLock)
UnLock ((BPTR) CurFLock);
if (*exit_msg)
WriteErrorString (ErrFmtStr, exit_msg);
PutStr (highlight_cursor.on);
Flush (Output ());
SetIoErr (result2);
/* this cleanup routine assumes that the C library will free all
malloc'd memory. This is true with SAS/C with standard exit(). */
exit ((int) exit_status);
}
static void AddAntiPattern (BYTE *pattern)
{
struct AnAntiPattern *AnAntiPattern = malloc (sizeof (struct AnAntiPattern));
int len = strlen (pattern) * 2 + 2;
if (!AnAntiPattern)
CleanUp (NoRAMMsg, RETURN_FAIL, ERROR_NO_FREE_STORE);
AnAntiPattern->next = TheAntiPatterns;
AnAntiPattern->pattern = pattern;
if (!(AnAntiPattern->parsedpattern = malloc (len)))
CleanUp (NoRAMMsg, RETURN_FAIL, ERROR_NO_FREE_STORE);
if (ParsePatternNoCase (pattern, AnAntiPattern->parsedpattern, len) == -1)
CleanUp (ParseErrorMsg, RETURN_FAIL, ERROR_NO_MORE_ENTRIES);
TheAntiPatterns = AnAntiPattern;
}
static void Usage (int full)
{
PutStr (shortusage);
if (full)
PutStr (fullusage);
CleanUp ("", full ? RETURN_WARN : RETURN_FAIL, ERROR_BAD_TEMPLATE);
}
#ifdef __SASC
void kput1 (void)
{
void __builtin_emit (int);
__builtin_emit (0x16C0); /* MOVE.B D0,(A3)+ */
}
#else
#error Fix kput1() for your compiler.
#endif
static void GetWinBounds (LONG *width, LONG *height, LONG have_console)
{
BPTR output = Output ();
char buffer[16];
if (have_console && output && IsInteractive (output) &&
SetMode (output, 1) && (Write (output, "\x9b" "0 q", 4) == 4) &&
WaitForChar (output, 10000L) &&
(Read (output, buffer, sizeof (buffer)) > 9) &&
(buffer[0] == '\x9b'))
{
int y = StrToLong (buffer + 5, height);
int x = StrToLong (buffer + 5 + y + 1, width);
if ((x == -1) || (y == -1))
goto TRY_ENV;
}
else
{
TRY_ENV:
if ((GetVar ("console_width", buffer, sizeof (buffer), LV_VAR | GVF_LOCAL_ONLY) == -1) ||
(StrToLong (buffer, width) == -1))
*width = 77;
if ((GetVar ("console_height", buffer, sizeof (buffer), LV_VAR | GVF_LOCAL_ONLY) == -1) ||
(StrToLong (buffer, height) == -1))
*height = 23;
}
if (have_console && output && IsInteractive (output))
SetMode (output, 0);
}
static int FillFibEntry (struct MinList *headfib, struct FileInfoBlock *fibp)
{
struct FibEntry *afib, *tfibp = malloc (sizeof (struct FibEntry));
if (!tfibp)
{
BREAKFLAG = 1;
return 0;
}
tfibp->fe_Fib = *fibp;
RemapDirEntryType (&(tfibp->fe_Fib));
for (afib = (struct FibEntry *) headfib->mlh_Head; afib->fe_Node.mln_Succ;
afib = (struct FibEntry *) afib->fe_Node.mln_Succ)
if (CompFibs (sortkey, &(tfibp->fe_Fib), &(afib->fe_Fib)))
break;
Insert ((struct List *) headfib, (struct Node *) tfibp, (struct Node *) afib->fe_Node.mln_Pred);
return 1;
}
static struct FibEntry *ModNextFib (struct FibEntry *tfibp, LONG rows)
{
LONG i;
for (i = 0; i < rows && tfibp->fe_Node.mln_Succ; i++)
tfibp = (struct FibEntry *) tfibp->fe_Node.mln_Succ;
return (tfibp);
}
static void SListDir (struct MinList *fibheadp)
{
LONG avglen;
LONG colcnt;
LONG dfcount;
LONG i, j, wlen;
LONG maxcol;
LONG maxrow;
LONG rowcnt;
LONG tlen;
LONG totlen;
struct FibEntry *hfibp, *tfibp;
for (totlen = dfcount = 0, hfibp = (struct FibEntry *) fibheadp->mlh_Head;
hfibp->fe_Node.mln_Succ;
hfibp = (struct FibEntry *) hfibp->fe_Node.mln_Succ)
{
totlen += strlen (hfibp->fe_Fib.fib_FileName) +
highlight_tab[hfibp->fe_Fib.fib_DirEntryType].printable_len;
dfcount++;
}
avglen = totlen / dfcount;
if (totlen % dfcount)
avglen++;
if ((CurWinCols) <= maxnamlen)
maxcol = 1;
else
for (maxcol = 0, colcnt = CurWinCols; colcnt >= avglen; maxcol++)
colcnt -= avglen + 2;
for (;;)
{
memset (padtab, 0, PADTABSIZE);
if (!(ACROSSLIST))
{
maxrow = dfcount / maxcol;
if (dfcount % maxcol)
maxrow++;
for (rowcnt = 0, hfibp = (struct FibEntry *) fibheadp->mlh_Head;
rowcnt < maxrow && hfibp->fe_Node.mln_Succ;
rowcnt++, hfibp = (struct FibEntry *) hfibp->fe_Node.mln_Succ)
{
for (colcnt = 0, tfibp = hfibp;
colcnt < maxcol && tfibp->fe_Node.mln_Succ;
colcnt++, tfibp = ModNextFib (tfibp, maxrow))
{
tlen = strlen (tfibp->fe_Fib.fib_FileName) +
highlight_tab[tfibp->fe_Fib.fib_DirEntryType].printable_len;
if (tlen > padtab[colcnt])
padtab[colcnt] = tlen;
}
if (!rowcnt)
{
maxcol = colcnt;
maxrow = dfcount / maxcol;
if (dfcount % maxcol)
maxrow++;
}
}
}
else
{
maxrow = dfcount / maxcol;
if (dfcount % maxcol)
maxrow++;
for (rowcnt = 0, tfibp = (struct FibEntry *) fibheadp->mlh_Head;
rowcnt < maxrow && tfibp->fe_Node.mln_Succ;
rowcnt++)
{
for (colcnt = 0;
colcnt < maxcol && tfibp->fe_Node.mln_Succ;
colcnt++, tfibp = (struct FibEntry *) tfibp->fe_Node.mln_Succ)
{
tlen = strlen (tfibp->fe_Fib.fib_FileName) +
highlight_tab[tfibp->fe_Fib.fib_DirEntryType].printable_len;
if (tlen > padtab[colcnt])
padtab[colcnt] = tlen;
}
}
}
for (colcnt = totlen = 0; (colcnt + 1) < maxcol; colcnt++)
totlen += (LONG) padtab[colcnt] + 2;
totlen += (LONG) padtab[colcnt];
if (maxcol > 1 && totlen > CurWinCols)
maxcol--;
else
break;
}
if (!(ACROSSLIST))
{
for (rowcnt = 0, hfibp = (struct FibEntry *) fibheadp->mlh_Head;
!(BREAKFLAG) && rowcnt < maxrow && hfibp->fe_Node.mln_Succ;
TestBreak (), rowcnt++, hfibp = (struct FibEntry *) hfibp->fe_Node.mln_Succ)
{
for (colcnt = 0, tfibp = hfibp;
colcnt < maxcol && tfibp->fe_Node.mln_Succ;
colcnt++)
{
workstr[0] = 0;
wlen = strlen (tfibp->fe_Fib.fib_FileName) +
highlight_tab[tfibp->fe_Fib.fib_DirEntryType].printable_len;
strcat (workstr, highlight_tab[tfibp->fe_Fib.fib_DirEntryType].on);
strcat (workstr, tfibp->fe_Fib.fib_FileName);
strcat (workstr, highlight_tab[tfibp->fe_Fib.fib_DirEntryType].off);
tfibp = ModNextFib (tfibp, maxrow);
if ((colcnt + 1) < maxcol && tfibp->fe_Node.mln_Succ)
{
for (i = (LONG) padtab[colcnt] + 1, j = strlen (workstr); i >= wlen; i--, j++)
workstr[j] = ' ';
workstr[j] = 0;
}
PutStr (workstr);
}
PutStr ("\n");
}
}
else
{
for (rowcnt = 0, tfibp = (struct FibEntry *) fibheadp->mlh_Head;
!(BREAKFLAG) && rowcnt < maxrow && tfibp->fe_Node.mln_Succ;
TestBreak (), rowcnt++)
{
for (colcnt = 0;
colcnt < maxcol && tfibp->fe_Node.mln_Succ;
colcnt++)
{
workstr[0] = 0;
wlen = strlen (tfibp->fe_Fib.fib_FileName) +
highlight_tab[tfibp->fe_Fib.fib_DirEntryType].printable_len;
strcat (workstr, highlight_tab[tfibp->fe_Fib.fib_DirEntryType].on);
strcat (workstr, tfibp->fe_Fib.fib_FileName);
strcat (workstr, highlight_tab[tfibp->fe_Fib.fib_DirEntryType].off);
tfibp = (struct FibEntry *) tfibp->fe_Node.mln_Succ;
if ((colcnt + 1) < maxcol && tfibp->fe_Node.mln_Succ)
{
for (i = (LONG) padtab[colcnt] + 1, j = strlen (workstr); i >= wlen; i--, j++)
workstr[j] = ' ';
workstr[j] = 0;
}
PutStr (workstr);
}
PutStr ("\n");
}
}
}
static void LListEntry (struct FileInfoBlock *fib)
{
BYTE *cp1, *cp2, *reps;
BYTE *pathend, *thenamestr;
LONG i, spccnt;
theprotstr[0] = "sL-L-ll-dd-DS"[fib->fib_DirEntryType + 7];
theprotstr[1] = (fib->fib_Protection & 128 /*FIBF_HIDDEN*/ )? 'h' : '-';
theprotstr[2] = (fib->fib_Protection & FIBF_SCRIPT) ? 's' : '-';
theprotstr[3] = (fib->fib_Protection & FIBF_PURE) ? 'p' : '-';
theprotstr[4] = (fib->fib_Protection & FIBF_ARCHIVE) ? 'a' : '-';
theprotstr[5] = (fib->fib_Protection & FIBF_READ) ? '-' : 'r';
theprotstr[6] = (fib->fib_Protection & FIBF_WRITE) ? '-' : 'w';
theprotstr[7] = (fib->fib_Protection & FIBF_EXECUTE) ? '-' : 'e';
theprotstr[8] = (fib->fib_Protection & FIBF_DELETE) ? '-' : 'd';
theprotstr[9] = ' ';
theprotstr[10] = fib->fib_Comment[0] ? 'c' : ' ';
DateStr (thedatestr, &(fib->fib_Date));
RawDoFmt (LongFmtStr, &fib->fib_NumBlocks, kput1, theblksstr);
RawDoFmt (LongFmtStr, &fib->fib_Size, kput1, thesizestr);
i = strlen (curpath);
pathend = curpath + i;
if (i > 1 && *(curpath + i - 1) != ':')
{
*(curpath + i) = '/';
i++;
*(curpath + i) = 0;
}
thenamestr = curpath + strlen (curpath);
cp2 = thenamestr;
if ((fib->fib_DirEntryType == HI_SOFTLINK) ||
(fib->fib_DirEntryType == HI_SOFTLINK_EXE))
{
struct DevProc *devproc = GetDeviceProc (curpath, NULL);
UBYTE buffer[512];
BOOL success;
cp2 = stpcpy (cp2, fib->fib_FileName);
if (devproc)
{
cp2 = stpcpy (cp2, " -> ");
success = ReadLink (devproc->dvp_Port, devproc->dvp_Lock,
fib->fib_FileName, buffer, 512);
if (success)
strcpy (cp2, buffer);
else
strcpy (cp2, "!ERROR READING LINK!");
FreeDeviceProc (devproc);
}
else
strcpy (cp2, "!ERROR LOCKING LINK!");
}
else if ((fib->fib_DirEntryType == HI_LINKDIR) ||
(fib->fib_DirEntryType == HI_LINKFILE) ||
(fib->fib_DirEntryType == HI_LINKFILE_EXE))
{
UBYTE buffer[512];
BPTR plock, lock;
plock = Lock (curpath, ACCESS_READ);
plock = CurrentDir (plock);
cp2 = stpcpy (cp2, fib->fib_FileName);
cp2 = stpcpy (cp2, " -> ");
lock = Lock (fib->fib_FileName, ACCESS_READ);
if (lock)
{
NameFromLock (lock, buffer, 512);
UnLock (lock);
strcpy (cp2, buffer);
}
else
strcpy (cp2, "!ERROR LOCKING LINK!");
plock = CurrentDir (plock);
UnLock (plock);
}
else
strcpy (cp2, fib->fib_FileName);
for (cp1 = workstr, cp2 = thefmtstr; *cp2; cp2++)
{
if (*cp2 != '%' && *cp2 != '\\')
*cp1++ = *cp2;
else
{
if (*cp2++ == '%')
{
if ((*cp2 >= '0') && (*cp2 <= '9'))
{
cp2 += StrToLong (cp2, &spccnt);
if (spccnt > 99)
spccnt = 99;
}
else
spccnt = 0;
switch (*cp2)
{
case 'p':
reps = theprotstr;
break;
case 'd':
reps = thedatestr;
break;
case 'b':
reps = theblksstr;
break;
case 's':
reps = thesizestr;
break;
case 'C':
if ((NOTEFLAG) && fib->fib_Comment[0])
{
cp1 = stpcpy (cp1, highlight_tab[HI_COMMENT].on);
cp1 = stpcpy (cp1, fib->fib_Comment);
cp1 = stpcpy (cp1, highlight_tab[HI_COMMENT].off);
}
reps = "";
break;
case 'w':
if ((NOTEFLAG) && fib->fib_Comment[0])
reps = wflag;
else
reps = "";
break;
case 'h':
RawDoFmt ("0x%lx", &fib->fib_Size, kput1, thehexsizestr);
reps = thehexsizestr;
break;
case 'S':
{
long xfer_rate;
int time[2];
cp2++;
if ((*cp2 >= '0') && (*cp2 <= '9'))
cp2 += StrToLong (cp2, &xfer_rate);
else
xfer_rate = 0;
cp2--;
if (!xfer_rate)
xfer_rate = 230;
time[0] = fib->fib_Size / xfer_rate / 60;
time[1] = fib->fib_Size / xfer_rate % 60;
RawDoFmt ("%ld:%02ld", time, kput1, thetimesizestr);
reps = thetimesizestr;
break;
}
case 'n':
if (FULLPATHNAMES)
reps = curpath;
else
reps = thenamestr;
break;
case '%':
*cp1++ = '%';
*cp1++ = 0;
default:
reps = "";
break;
}
for (i = strlen (reps); i < spccnt; i++)
*cp1++ = ' ';
cp1 = stpcpy (cp1, reps);
}
else
{
switch (*cp2)
{
case 'n':
*cp1++ = '\n';
break;
case '"':
*cp1++ = '"';
break;
case 't':
*cp1++ = '\t';
break;
case '\\':
*cp1++ = '\\';
break;
default:
break;
}
}
}
}
*cp1 = 0;
PutStr (workstr);
*pathend = 0;
}
static void LListDir (struct MinList *fibheadp)
{
struct FibEntry *tfibp;
totblocks = totbytes = 0;
for (tfibp = (struct FibEntry *) fibheadp->mlh_Head;
tfibp->fe_Node.mln_Succ;
tfibp = (struct FibEntry *) tfibp->fe_Node.mln_Succ)
{
TestBreak ();
if (BREAKFLAG)
return;
LListEntry (&(tfibp->fe_Fib));
if (tfibp->fe_Fib.fib_DirEntryType < 0)
{
totblocks += tfibp->fe_Fib.fib_NumBlocks;
totbytes += tfibp->fe_Fib.fib_Size;
}
}
if (!(BREAKFLAG || NOHEADERS))
VPrintf (totalfmtstr, &dircount); /* note that parameters are in order in memory */
}
static void FreeAllFibs (struct MinList *fibheadp)
{
struct FibEntry *tfibp;
if (fibheadp)
{
while (fibheadp->mlh_Head->mln_Succ)
{
tfibp = (struct FibEntry *) RemTail ((struct List *) fibheadp);
free (tfibp);
}
}
}
static struct MinList *GetDir (struct FileLock *lockp, struct FileInfoBlock *fibp)
{
struct AnAntiPattern *theanti;
LONG matchstat;
LONG nextstat;
LONG tempnamlen;
struct MinList *fibhead;
struct MinList *dirhead;
maxnamlen = dircount = filecount = 0L;
if (!(fibhead = malloc (sizeof (struct MinList))))
return (0L);
NewList ((struct List *) fibhead);
if (!(dirhead = malloc (sizeof (struct MinList))))
goto BADALLOC;
NewList ((struct List *) dirhead);
do
{
TestBreak ();
if (BREAKFLAG)
goto GOODRET;
if (nextstat = ExNext ((BPTR) lockp, fibp))
{
if (CmpDateBounds (&fibp->fib_Date))
{
if ((fibp->fib_DirEntryType >= 0) &&
(!(fibp->fib_DirEntryType == ST_SOFTLINK)))
matchstat = MatchPatternNoCase (theDirPatParsed, fibp->fib_FileName);
else
matchstat = MatchPatternNoCase (theFilePatParsed, fibp->fib_FileName);
if (!(SHOWHIDDEN) && matchstat)
matchstat = !(fibp->fib_Protection & 128 /*FIBF_HIDDEN*/ );
theanti = TheAntiPatterns;
while (matchstat && theanti)
{
matchstat = !MatchPatternNoCase (theanti->parsedpattern, fibp->fib_FileName);
theanti = theanti->next;
}
if (!matchstat)
continue;
if ((fibp->fib_DirEntryType >= 0) &&
(!(fibp->fib_DirEntryType == ST_SOFTLINK)))
{
if (!FillFibEntry (dirhead, fibp))
goto BADALLOC;
if (HIDEDIRS)
continue;
dircount++;
gdircount++;
}
else
{
filecount++;
gfilecount++;
gtotblocks += fibp->fib_NumBlocks;
gtotbytes += fibp->fib_Size;
}
tempnamlen = strlen (fibp->fib_FileName);
if (tempnamlen > maxnamlen)
maxnamlen = tempnamlen;
if (!FillFibEntry (fibhead, fibp))
goto BADALLOC;
}
}
}
while (nextstat);
if (IoErr ()!= ERROR_NO_MORE_ENTRIES)
CleanUp (ExNextMsg, RETURN_FAIL, IoErr ());
if (dircount + filecount)
{
if (!(LONGLIST))
SListDir (fibhead);
else
LListDir (fibhead);
}
GOODRET:
FreeAllFibs (fibhead);
return (dirhead);
BADALLOC:
FreeAllFibs (fibhead);
FreeAllFibs (dirhead);
return (0L);
}
static void DirIt (struct FileLock *curlock, BYTE *dirname)
{
BYTE *subdir;
size_t dnamlen;
struct FibEntry *tfibp;
struct FileLock *sublock;
struct MinList *fibheadp;
struct FileInfoBlock __aligned GFibp;
if (!Examine ((BPTR) curlock, &GFibp))
{
WriteErrorString (NoExamFmtStr, IoErr ());
return;
}
if (dirname[0] && (LISTALL) && !(NOHEADERS))
{
PutStr (highlight_tab[HI_LABEL].on);
PutStr (dirname);
PutStr ("\n");
PutStr (highlight_tab[HI_LABEL].off);
}
if ((GFibp.fib_DirEntryType < 0) ||
(GFibp.fib_DirEntryType == ST_SOFTLINK) || (ABOUTDIRS))
{
RemapDirEntryType (&GFibp);
*(PathPart (thePath)) = '\0';
LListEntry (&GFibp);
filecount++;
gfilecount++;
gtotblocks += GFibp.fib_NumBlocks;
gtotbytes += GFibp.fib_Size;
}
else
{
if (fibheadp = GetDir (curlock, &GFibp))
{
if (LISTALL)
{
for (tfibp = (struct FibEntry *) fibheadp->mlh_Head;
tfibp->fe_Node.mln_Succ;
tfibp = (struct FibEntry *) tfibp->fe_Node.mln_Succ)
{
TestBreak ();
if (BREAKFLAG)
break;
dnamlen = (strlen (dirname) + strlen (tfibp->fe_Fib.fib_FileName) + 36);
if (subdir = malloc (dnamlen))
{
if (dirname[0])
{
strcpy (subdir, dirname);
dnamlen = strlen (dirname) - 1;
if (dirname[dnamlen] != ':' && dirname[dnamlen] != '/')
strcat (subdir, "/");
}
strcat (subdir, tfibp->fe_Fib.fib_FileName);
if (sublock = (struct FileLock *) Lock (subdir, (LONG) ACCESS_READ))
{
if (!(NOHEADERS))
PutStr ("\n");
curpath = subdir;
DirIt (sublock, subdir);
UnLock ((BPTR) sublock);
}
free (subdir);
}
}
}
FreeAllFibs (fibheadp);
}
}
}
static void GetCLIArgs (BYTE *line, LONG *argc, BYTE **argv)
{
BYTE **pargv, *qarg;
*argc = 0;
while (*argc < MAXARG)
{
while (*line == ' ' || *line == '\t' || *line == '\n')
line++;
if (!(*line))
break;
pargv = &argv[*argc];
*argc += 1;
if (*line == '"')
{
qarg = line;
line += 1;
*pargv = line;
while (*line && *line != '"')
if (*line == '\\' && *(line + 1))
line += 2;
else
line++;
if (!(*line))
{
*pargv = qarg;
break;
}
else
*line++ = 0;
}
else
{
*pargv = line;
while (*line && !(*line == ' ' || *line == '\t' || *line == '\n'))
line++;
if (*line)
*line++ = 0;
else
break;
}
}
}
static LONG ParseCmdOptions (LONG ncnt, LONG argc, BYTE **argv)
{
LONG i, cnt, len;
cnt = ncnt;
ncnt += 1;
for (i = 1, len = strlen (argv[cnt]); i < len; i++)
{
switch (argv[cnt][i])
{
case '?':
case 'h':
Usage (1);
break;
case 'D':
FILESFIRST = 1;
break;
case 'F':
if (argc < (ncnt + 1))
goto missing_arg_error;
thefmtstr = argv[ncnt];
ncnt += 1;
LONGLIST = 1;
break;
case 'H':
NOHEADERS = 1;
break;
case 'A':
ACROSSLIST = 1;
break;
case 'M':
MIXFILESDIRS = 1;
break;
case 'N':
if (argc < (ncnt + 1))
goto missing_arg_error;
if (StrDate (argv[ncnt], &thenewdate))
goto date_arg_error;
ncnt += 1;
SHOWNEWERTHAN = 1;
break;
case 'O':
if (argc < (ncnt + 1))
goto missing_arg_error;
if (StrDate (argv[ncnt], &theolddate))
goto date_arg_error;
ncnt += 1;
SHOWOLDERTHAN = 1;
break;
date_arg_error:
WriteErrorString (NotGoodDateStr, argv[ncnt]);
CleanUp ("", RETURN_FAIL, ERROR_BAD_TEMPLATE);
case 'P':
if ((thefmtstr == deffmtstr) && !(LONGLIST))
thefmtstr = deffullstr;
FULLPATHNAMES = 1;
LONGLIST = 1;
NOHEADERS = 1;
break;
case 'R':
LISTALL = 1;
break;
case 'T':
TOTALIZE = 1;
break;
case 'X':
if (argc < (ncnt + 1))
goto missing_arg_error;
StrToLong (argv[ncnt], &CurWinCols);
ncnt += 1;
break;
case 'w':
if (argc < (ncnt + 1))
goto missing_arg_error;
wflag = argv[ncnt];
ncnt += 1;
break;
case '1':
CurWinCols = 1;
break;
case 'Y':
if (argc < (ncnt + 1))
goto missing_arg_error;
ncnt += 1;
break;
case 'a':
SHOWHIDDEN = 1;
break;
case 'c':
LONGLIST = 1;
NOTEFLAG = 1;
break;
case 'd':
ABOUTDIRS = 1;
break;
case 'e':
sortkey = sort_extension;
break;
case 'f':
HIDEDIRS = 1;
break;
case 'k':
CONSOLE = 0;
break;
case 'l':
if ((thefmtstr == deffullstr) && (FULLPATHNAMES))
thefmtstr = deffmtstr;
LONGLIST = 1;
break;
case 'n':
sortkey = sort_none;
break;
case 'r':
REVFLAG = 1;
break;
case 's':
sortkey = sort_size;
break;
case 't':
sortkey = sort_date;
break;
case 'I':
if (argc < (ncnt + 1))
goto missing_arg_error;
AddAntiPattern (argv[ncnt]);
ncnt += 1;
break;
default:
WriteErrorString (BadOptFmtStr, argv[cnt][i]);
Usage (0);
missing_arg_error:
WriteErrorString (OptNeedsArgStr, argv[cnt][i]);
Usage (1);
}
}
return (ncnt);
}
void __stdargs __main (char *line)
{
BYTE *argv[MAXARG];
LONG argc;
LONG cnt = 1;
LONG Columns, Rows;
SHORT namedPath = FALSE;
if (DOSBase->dl_lib.lib_Version < 37)
{
Write (Output (), "ls: Need AmigaOS Release 2.04\n", 30);
exit (20);
}
GetCLIArgs (line, &argc, argv);
if (IsInteractive (Output ()))
CONSOLE = 1;
while (cnt < argc && argv[cnt][0] == '-')
{
if (argv[cnt][1] == '-' || argv[cnt][1] == '\0')
{
cnt++;
break;
}
else
{
cnt = ParseCmdOptions (cnt, argc, argv);
continue;
}
}
{
int i;
char a[32], *b;
if (!(b = malloc (32)))
CleanUp (NoRAMMsg, RETURN_FAIL, ERROR_NO_FREE_STORE);
for (i = HIGHLIGHT_MIN; i <= HIGHLIGHT_MAX; i++)
{
RawDoFmt ("ls_highlight%ld.on", &i, kput1, a);
if (GetVar (a, b, 32, LV_VAR | GVF_LOCAL_ONLY) != -1)
{
highlight_tab[i].on = b;
highlight_tab[i].printable_len = 0;
for (; *b; b++)
{
if ((*b == '\x9b') || (*b == '\x1b'))
{
while (*++b)
if (*b == 'm')
break;
}
else
highlight_tab[i].printable_len++;
}
if (!(b = malloc (32)))
CleanUp (NoRAMMsg, RETURN_FAIL, ERROR_NO_FREE_STORE);
RawDoFmt ("ls_highlight%ld.off", &i, kput1, a);
if (GetVar (a, b, 32, LV_VAR | GVF_LOCAL_ONLY) != -1)
{
highlight_tab[i].off = b;
for (; *b; b++)
{
if ((*b == '\x9b') || (*b == '\x1b'))
{
while (*++b)
if (*b == 'm')
break;
}
else
highlight_tab[i].printable_len++;
}
if (!(b = malloc (32)))
CleanUp (NoRAMMsg, RETURN_FAIL, ERROR_NO_FREE_STORE);
}
}
}
free (b);
}
if (!(CONSOLE))
{
int i;
for (i = HIGHLIGHT_MIN; i <= HIGHLIGHT_MAX; i++)
if ((*highlight_tab[i].on == '\x9b') ||
(*highlight_tab[i].on == '\x1b') ||
(*highlight_tab[i].off == '\x9b') ||
(*highlight_tab[i].off == '\x1b'))
highlight_tab[i] = highlight_null;
highlight_cursor = highlight_null;
highlight_tab[HI_COMMENT].on = "/* ";
highlight_tab[HI_COMMENT].off = " */";
}
{
char b[32];
if (!(SHOWHIDDEN))
if (GetVar ("ls_hidepattern", b, sizeof b, LV_VAR | GVF_LOCAL_ONLY) != -1)
AddAntiPattern (b);
else
AddAntiPattern ("(#?.(info|bak)|.#?)");
}
if (!CurWinCols)
{
GetWinBounds (&Columns, &Rows, (CONSOLE));
CurWinCols = Columns;
}
PutStr (highlight_cursor.off);
while (!(BREAKFLAG))
{
if (cnt < argc)
{
namedPath = TRUE;
theFilePat[0] = 0;
theDirPat[0] = 0;
strcpy (thePath, argv[cnt]);
cnt++;
if (ParsePatternNoCase (thePath, theDirPatParsed, sizeof (theDirPatParsed)))
{
strcpy (theFilePat, FilePart (thePath));
strcpy (theDirPat, theFilePat);
*(PathPart (thePath)) = '\0';
if (ParsePatternNoCase (thePath, theDirPatParsed, sizeof (theDirPatParsed)))
{
strcpy (theDirPat, FilePart (thePath));
*(PathPart (thePath)) = '\0';
}
}
if (ParsePatternNoCase (thePath, theDirPatParsed, sizeof (theDirPatParsed)))
CleanUp (NoWildPathMsg, RETURN_WARN, ERROR_NO_MORE_ENTRIES);
if (!(CurFLock = (struct FileLock *) Lock (thePath, (LONG) ACCESS_READ)))
{
WriteErrorString (NoFindFmtStr, thePath);
CleanUp ("", RETURN_FAIL, IoErr ());
}
}
else if ((!namedPath) && (cnt == argc))
{
struct Process *procp = (struct Process *) FindTask (0L);
cnt++;
if (procp->pr_CurrentDir)
CurFLock = (struct FileLock *) DupLock (procp->pr_CurrentDir);
else
CurFLock = (struct FileLock *) Lock ("sys:", ACCESS_READ);
if (!CurFLock)
CleanUp (NoCurrentDirMsg, RETURN_FAIL, ERROR_NO_DEFAULT_DIR);
}
else
break;
if (!strchr (thePath, ':'))
if (!NameFromLock ((BPTR) CurFLock, thePath, sizeof (thePath)))
CleanUp (NameFromLockMsg, RETURN_FAIL, IoErr ());
curpath = thePath;
if (!theDirPat[0])
strcpy (theDirPat, "#?");
if (!theFilePat[0])
strcpy (theFilePat, "#?");
if (ParsePatternNoCase (theDirPat, theDirPatParsed, sizeof (theDirPatParsed)) == -1)
CleanUp (ParseErrorMsg, RETURN_FAIL, ERROR_NO_MORE_ENTRIES);
if (ParsePatternNoCase (theFilePat, theFilePatParsed, sizeof (theFilePatParsed)) == -1)
CleanUp (ParseErrorMsg, RETURN_FAIL, ERROR_NO_MORE_ENTRIES);
DirIt (CurFLock, thePath);
if (CurFLock)
UnLock ((BPTR) CurFLock);
CurFLock = NULL;
TestBreak ();
}
if ((TOTALIZE))
{
PutStr (highlight_tab[HI_LABEL].on);
PutStr (TotHeaderMsg);
PutStr (highlight_tab[HI_LABEL].off);
VPrintf (totalfmtstr, &gdircount); /* note that parameters are in order in memory */
}
CleanUp ("", RETURN_OK, 0L);
}